home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / languags / a68k242.4 < prev    next >
Text File  |  1989-03-08  |  56KB  |  1,852 lines

  1. Path: xanth!ukma!tut.cis.ohio-state.edu!mailrus!bbn!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i026:  a68k - 68000 assembler v2.42, Part04/04
  5. Message-ID: <12037@swan.ulowell.edu>
  6. Date: 8 Mar 89 01:50:35 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1841
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: jlydiatt@jlami.wimsey.bc.ca (Jeff Lydiatt)
  12. Posting-number: Volume 89, Issue 26
  13. Archive-name: languages/a68k242.4
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    Symtab.c
  23. #    Operands.c
  24. # This archive created: Tue Mar  7 20:42:31 1989
  25. cat << \SHAR_EOF > Symtab.c
  26. /*------------------------------------------------------------------*/
  27. /*                                    */
  28. /*              MC68000 Cross Assembler                */
  29. /*                                    */
  30. /*          Copyright    (c) 1985 by Brian R. Anderson            */
  31. /*                                    */
  32. /*       Symbol table    manipulation - January 6, 1989            */
  33. /*                                    */
  34. /*   This program may be copied    for personal, non-commercial use    */
  35. /*   only, provided that the above copyright notice is included        */
  36. /*   on    all copies of the source code.    Copying    for any    other use   */
  37. /*   without the consent of the    author is prohibited.            */
  38. /*                                    */
  39. /*------------------------------------------------------------------*/
  40. /*                                    */
  41. /*        Originally published (in Modula-2) in            */
  42. /*        Dr.    Dobb's Journal, April, May, and June 1986.          */
  43. /*                                    */
  44. /*     AmigaDOS conversion copyright 1989 by Charlie Gibbs.        */
  45. /*                                    */
  46. /*------------------------------------------------------------------*/
  47.  
  48. #include <stdio.h>
  49. #include "a68kdef.h"
  50. #include "a68kglb.h"
  51.  
  52. long Value;    /* Passed from ReadSymTab to CalcValue */
  53.  
  54. /* Functions */
  55. extern int  Instructions(), ObjDir();
  56. extern int  GetInstModeSize(), GetMultReg();
  57. extern int  GetArgs(), GetAReg();
  58. extern long AddrBndW(),    AddrBndL();
  59. char *AddName();
  60. struct SymTab *NextSym();
  61. struct SymTab **HashIt();
  62.  
  63. int  LineParts(), ReadSymTab(),    OpenIncl(), CountNest();
  64. long GetValue(), CalcValue();
  65. char *GetField();
  66.  
  67.  
  68.  
  69. int OpenIncl (name, dirlist) char *name, *dirlist;
  70. /* Opens the file whose    name is    in "name".  The current
  71.     directory is tried first.  If that fails, the directory
  72.     names in "dirlist" (separated by commas) are then tried
  73.     until either a file    is found or the    list is    exhausted.
  74.     If the file    is found in a subdirectory, "name" is
  75.     modified to    include    the entire path    specification.
  76.     If another input file is open when this routine is called,
  77.     it is closed first.     Returns TRUE if successful, FALSE if not.  */
  78. {
  79.     register char *s, *t;
  80.     char dirname[MAXLINE];
  81.  
  82.     if (In.fd != NULL)
  83.     close (In.fd);        /* Close the inner file    */
  84.  
  85.     if ((In.fd = open (name, 0)) != -1)    {
  86.     In.Ptr = In.Lim    = In.Buf;
  87.     if (Quiet < 0)
  88.         fprintf (stderr, "\n%s line ", name);
  89.     return (TRUE);        /* Found it in current directory */
  90.     }
  91.     s =    dirlist;
  92.     while (*s) {
  93.     s = GetField (s, dirname);
  94.     t = dirname + strlen (dirname) - 1;
  95.     if ((*t    != '/') && (*t != ':'))
  96.         strcat (dirname, "/");      /* Slash after directory name */
  97.     strcat (dirname, name);
  98.     if ((In.fd = open (dirname, 0))    != -1) {
  99.         In.Ptr = In.Lim = In.Buf;
  100.         strcpy (name, dirname);    /* Return entire path */
  101.         if (Quiet <    0)
  102.         fprintf    (stderr, "\n%s line ", name);
  103.         return (TRUE);    /* Found it in a subdirectory */
  104.     }
  105.     if (*s)
  106.         s++;        /* Skip    over separator and try again */
  107.     }
  108.     In.fd = NULL;
  109.     return (FALSE);        /* Couldn't find it anywhere */
  110. }
  111.  
  112.  
  113.  
  114. int LineParts (dummy) int dummy;
  115. /* Gets    the next statement and extracts    its component parts.
  116.     If end of file is reached, and we're in a macro or include
  117.     file, the file is closed and the next outermost file is
  118.     continued.    If we have reached the end of the source file, or
  119.     encounter an ENDM or MEXIT directive within    a macro    expansion,
  120.     the    current    input file is closed and TRUE is returned.
  121.  
  122.     If we're in a user macro (indicated by UPtr being nonzero),
  123.     we'll get the next statement from the save area in memory instead.
  124.  
  125.     Macro arguments, if    any, are substituted.
  126.  
  127.     LineCount is incremented if    a statement was    successfully read.
  128.  
  129.     If this is the first call of this routine (i.e. LineCount is zero)
  130.     and    HeaderFN is not    a null string, we'll return an INCLUDE statement
  131.     requesting the specified header file, rather than reading the first
  132.     statement from the source file.
  133.  
  134.     The    following fields are set up:
  135.     Line    - statement line image
  136.     Label    - instruction label (without trailing colon)
  137.     OpCode    - instruction mnemonic (converted to upper case)
  138.     SrcOp    - first    (source) operand
  139.     DestOp    - second (destination) operand
  140.     Size    - size from OpCode
  141.     LabLoc    - displacement to start    of instruction label
  142.     OpLoc    - displacement to start    of instruction mnemonic
  143.     SrcLoc    - displacement to start    of source operand
  144.     DestLoc    - displacement to start    of destination operand
  145.     InFNum    - decremented if end of    file is    reached
  146.     InF    - incremented if end of    file is    reached
  147.     LabLine    - set to LineCount if this line    is labeled
  148.             (unless    it's a local label)
  149.                                 */
  150. {
  151.     register int i, c;
  152.     int    eofflag;
  153.     char *x;
  154.  
  155.  
  156.     while (1) {    /* Repeat until    we get something (not end of INCLUDE) */
  157.     Line[0]    = Label[0] = OpCode[0] = SrcOp[0] = DestOp[0] =    '\0';
  158.     LabLoc = OpLoc = SrcLoc    = DestLoc = 0;
  159.     Src.Mode = Dest.Mode = NULL;
  160.     FwdShort = FALSE;
  161.  
  162.     if ((LineCount==0) && (HeaderFN[0])) {    /* Header file */
  163.         strcpy (Line, "        INCLUDE ");  /* Make an INCLUDE stmt. */
  164.         strcat (Line, HeaderFN);
  165.         strcat (Line, "        ;Generated for header file");
  166.         strcpy (OpCode, "INCLUDE"); /* Dummy op code */
  167.         OpLoc = 8;
  168.         strcpy (SrcOp, HeaderFN);    /* Dummy source    operand    */
  169.         SrcLoc = 16;
  170.         LineCount++;
  171.         ErrLim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  172.         PrntAddr = FALSE;
  173.         return (FALSE);
  174.     }
  175.  
  176.     if (InF->UPtr != 0) {            /* User    macro input */
  177.         GetMacLine (dummy);
  178.         eofflag = FALSE;
  179.     } else {                /* Normal file input */
  180.         eofflag = GetLine (dummy);
  181.     }
  182.     if ((Line[0] !=    '\0') && (Line[0] != '*') && (Line[0] != ';')) {
  183.         SubArgs (dummy);    /* Substitute macro arguments */
  184.         GetParts (dummy);    /* Break Line into its component parts */
  185.     }
  186.  
  187.     /* ------ If we    have reached the end of    a macro    or ------ */
  188.     /* ------ include file,    return to the calling file ------ */
  189.  
  190.     i = eofflag;                /* End of file */
  191.  
  192.     if (i) {
  193.         if (SkipNest != 0) {
  194.         Error (OpLoc, NoENDC);    /* ENDC    is missing */
  195.         WriteListLine (&List);    /* It's not normally listed */
  196.         SkipNest = 0;
  197.         }
  198.     } else if ((InF->NArg != -1)&&(Dir != Macro)) {    /* Macro exits */
  199.         if (strcmp (OpCode,    "ENDM") == 0) {
  200.         i = TRUE;
  201.         (InF->Line)++;        /* Count ENDM directive    */
  202.         if (SkipNest !=    0) {
  203.             Error (OpLoc, NoENDC);  /* ENDC is missing */
  204.             WriteListLine (&List);  /* It's not normally listed */
  205.             SkipNest = 0;
  206.         }
  207.         } else if (SkipNest    == 0) {
  208.         if (strcmp (OpCode, "MEXIT") == 0) {
  209.             i =    TRUE;
  210.             (InF->Line)++;    /* Count MEXIT directive */
  211.         }
  212.         }
  213.     }
  214.     if (!i)    {            /* Not end of file or macro */
  215.         if (PrevDir    == MacCall) {
  216.         if (strcmp (OpCode, "MACRO") == 0) {
  217.             (InF->Line)++;    /* Count macro header */
  218.             continue;        /*  and    ignore it.    */
  219.         }
  220.         }
  221.         if (SkipNest == 0) {    /* If we're not skipping, */
  222.         break;            /*  we got something.      */
  223.         } else {
  224.         (InF->Line)++;        /* Count skipped lines */
  225.         SkipNest += CountNest (OpCode);    /* Adjust SkipNest */
  226.         continue;
  227.         }
  228.     }
  229.     if (!Pass2 && (IncStart    != 0) && (IncPtr == InF)) {
  230.         SkipLim->Start = IncStart;    /* End of skippable INCLUDE */
  231.         SkipLim->Finish=LineCount;    /* Save    line numbers for pass 2    */
  232.         SkipLim->MCount = MacCount;    /* Save    macro counter too */
  233.         if (SkipLim->Set1 != NULL) {
  234.         SetFixLim--;
  235.         x = (char *) SkipLim + sizeof (struct SkipEnt);
  236.         if (x >    (char *) SetFixLim) {
  237.             SetFixLim++;    /* No room for final entry */
  238.         } else {
  239.             SetFixLim->Sym  = NULL;    /* Null    entry         */
  240.             SetFixLim->Val  = 0;    /*  indicates end of */
  241.             SetFixLim->Hunk = 0;    /*  SET    symbol list. */
  242.         }
  243.         }
  244.         SkipLim++;
  245.         IncStart = 0;
  246.     }
  247.     if (InFNum == 0)
  248.         break;            /* End of source file */
  249.     if (i =    (InF->UPtr == 0)) {
  250.         if (Quiet <    0)
  251.         fprintf    (stderr, "%d\n", InF->Line);
  252.         close (In.fd);        /* Close inner file */
  253.         In.fd = NULL;
  254.     }
  255.     NextFNS    = InF->NPtr;        /* Release space on name stack */
  256.     InFNum--;            /* Return to outer file    */
  257.     InF++;
  258.     if (InFNum < OuterMac)
  259.         OuterMac = 0;        /* End of outer    macro */
  260.     if (InF->UPtr == 0) {
  261.         if (i)
  262.         ShowFile (FALSE);    /* Inner file -> outer file */
  263.         else if (InnrFMac) {
  264.         ShowFile (FALSE);    /* Inner user macro -> file */
  265.         InnrFMac = FALSE;
  266.         }
  267.         if (In.fd == NULL) {
  268.         In.fd =    open (InF->NPtr, 0);
  269.         lseek (In.fd, InF->Pos,    0);
  270.         In.Ptr = In.Lim    = In.Buf;
  271.         }
  272.     } else if (i) {
  273.         InnrFMac = TRUE;    /* Inner file -> outer user macro */
  274.     }
  275.     }
  276.     LineCount++;            /* Bump    line counter */
  277.     (InF->Line)++;
  278.     if ((Label[0] != '\0') && (Label[0] != '\\'))
  279.     if ((Label[0] <    '0') || (Label[0] > '9'))
  280.         LabLine = LineCount;    /* Save    line number of label */
  281.     if (Quiet != 0) {
  282.     i = (Quiet < 0 ? InF->Line : LineCount);
  283.     if ((i % Quiet)    == 0) {        /* Display progress */
  284.         ShowLine (i);
  285.     }
  286.     }
  287.     ErrLim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  288.     PrntAddr = FALSE;
  289.  
  290.     if (LineCount == DebugStart)
  291.     fprintf    (stderr, "%d\n", LineCount);
  292.     if ((LineCount >= DebugStart) && (LineCount    <= DebugEnd))
  293.     printf ("%9lx %5d %s\n", AddrCnt, LineCount, Line);
  294.  
  295.     return (eofflag);
  296. }
  297.  
  298.  
  299.  
  300. GetMacLine (dummy) int dummy;
  301. /* Gets    the next stored    user macro line. */
  302. {
  303.     register char *s, *t;
  304.     register struct NameChunk *np;
  305.  
  306.     s =    InF->UPtr;
  307.     if (*s == '\n') {           /* Continue in next chunk */
  308.     np = NameStart;
  309.     while ((s < (char *) np)
  310.     || (s >    ((char *) np + CHUNKSIZE)))
  311.         np = np->Link;    /* Find    the chunk we're in */
  312.     InF->UPtr = (char *) (np->Link)    + sizeof (struct NameChunk *);
  313.     s = InF->UPtr;
  314.     }
  315.     t =    Line;
  316.     while (*t++    = *s++)    /* Copy    InF->UPtr to Line, then    bump InF->UPtr.    */
  317.     ;        /*  (It's faster than doing a strcpy followed   */
  318.     InF->UPtr =    s;    /*  by a strlen    to bump    the pointer.)        */
  319. }
  320.  
  321.  
  322.  
  323. int GetLine (dummy) int    dummy;
  324. /* Gets    the next line from the current input file and leaves it    in Line.
  325.     Returns TRUE if end    of file    has been reached, FALSE    otherwise.    */
  326. {
  327.     register char *s;
  328.     register int c;
  329.     register char *t, *m, *l;
  330.  
  331.     s =    Line;
  332.     t =    In.Ptr;                /* Use a register for speed */
  333.     m =    Line + MAXLINE - 1;        /* Limit of "Line" */
  334.     while (1) {                /* Get Line, expanding tabs */
  335.     if (t >= In.Lim) {
  336.         t =    In.Buf;            /* Re-fill the buffer */
  337.         In.Lim = In.Buf + read (In.fd, In.Buf, BUFFSIZE);
  338.         if (In.Lim == In.Buf) {
  339.         *s = '\0';              /* End of file */
  340.         In.Ptr = t;
  341.         return (s <= Line);    /* Last    line might have    no \n */
  342.         }
  343.     }
  344.     if ((c = *t++) == '\n') {
  345.         break;
  346.     }
  347. #ifdef MSDOS
  348.     if (c == 26) {
  349.         *s = '\0';                  /* Catch MS-DOS EOF char. */
  350.         In.Ptr = t;
  351.         return (s <= Line);
  352.     }
  353.     if ((s < m) && (c != 13)) {    /* Ignore excess */
  354. #else
  355.     if (s <    m) {            /* Ignore excess */
  356. #endif
  357.         if ((c == '\t') && !KeepTabs) {
  358.         l = Line + (((s    - Line)    + 8) & ~7);
  359.         if (l >    m)
  360.             l =    m;        /* Tabbed off the end */
  361.         while (s < l)
  362.             *s++ = ' ';         /* Expand tabs */
  363.         } else {
  364.         *s++ = c;        /* Normal character */
  365.         }
  366.     }
  367.     }
  368.     *s = '\0';                  /* Terminate the string in Line */
  369.     In.Ptr = t;
  370.     return (FALSE);
  371. }
  372.  
  373.  
  374.  
  375. SubArgs    (dummy)    int dummy;
  376. /* Macro argument substitution routine */
  377. {
  378.     int    j;
  379.     register char *s, *t, *x;
  380.     char subline[MAXLINE];
  381.  
  382.     if (InF->NArg == -1)
  383.     return;            /* Not a macro - leave Line alone */
  384.  
  385.     s =    Line;
  386.     t =    subline;
  387.     while (*s) {
  388.     if ((*t++ = *s++) != '\\') {
  389.         continue;
  390.     }
  391.     x = s--;
  392.     t--;
  393.     if (*x == '@') {        /* \@ - substitute macro number */
  394.         x =    t;
  395.         *t++ = '.';
  396.         j =    InF->MCnt % 1000;
  397.         *t++ = j / 100 + '0';
  398.         j =    j % 100;
  399.         *t++ = j / 10 + '0';
  400.         *t++ = j % 10 + '0';
  401.         strcpy (t, s+2);        /* Remainder of    Line */
  402.         strcpy (Line, subline);    /* Replace Line    */
  403.         while (*t != '\\')          /* Check for more substitutions */
  404.         if (*t)
  405.             t++;
  406.         else
  407.             return;        /* All done */
  408.         s =    t - subline + Line;    /* Do the next substitution */
  409.         continue;
  410.     }
  411.     if ((*x    < '0') || (*x > '9')) {
  412.         s++;        /* False alarm - it's a  */
  413.         t++;        /*  named local    variable */
  414.         continue;
  415.     }
  416.  
  417.     s++;
  418.     *t = '\0';
  419.     j = 0;            /* Get argument    index */
  420.     while ((*s >= '0') && (*s <= '9')) {
  421.         j *= 10;
  422.         j += *s++ -    '0';    /* Current digit */
  423.     }
  424.     if (j == 0)
  425.         strcpy (t, MacSize);    /* Macro call size */
  426.     else if    ((j > 0) && (j <= InF->NArg)) {
  427.         x =    InF->NPtr;
  428.         while (j > 0) {        /* Find    argument */
  429.         x += strlen (x)    + 1;
  430.         j--;
  431.         }
  432.         strcpy (t, x);        /* Insert it */
  433.     }
  434.     while (*t)
  435.         t++;            /* Skip    over replacement */
  436.     strcpy (t, s);            /* Remainder of    Line */
  437.     strcpy (Line, subline);        /* Replace Line    */
  438.     while (*t != '\\')              /* Check for more substitutions */
  439.         if (*t)
  440.         t++;
  441.         else
  442.         return;            /* All done */
  443.     s = t -    subline    + Line;        /* Do the next substitution */
  444.     }
  445. }
  446.  
  447.  
  448.  
  449. GetParts (dummy) int dummy;
  450. /* Break up Line into its component parts. */
  451. {
  452.     register char *s, *x;
  453.  
  454.     Size = S0;
  455.     s =    Line;
  456.     if (!isspace (*s)) {
  457.     x = Label;
  458.     while (!isspace    (*s) &&    (*s != ';') && (*s != '\0'))
  459.         *x++ = *s++;        /* Get the label */
  460.     *x-- = '\0';
  461.     while (*x == ':') {
  462.         *x-- = '\0';                /* Strip trailing colon(s) */
  463.         if (x < Label)
  464.         break;
  465.     }
  466.     }
  467.     while (OpLoc == 0) {
  468.     while (isspace (*s))
  469.         s++;            /* Skip    over to    opcode */
  470.     if ((*s    == ';') || (*s == '\0'))
  471.         return;            /* End of statement image */
  472.     OpLoc =    s - Line;
  473.     x = OpCode;
  474.     while (!isspace    (*s) &&    (*s != ';') && (*s != '\0'))
  475.         *x++ = *s++;        /* Get the opcode */
  476.     *x-- = '\0';
  477.     if (*x == ':') {                /* It's actually a label */
  478.         if (Label[0]) {
  479.         Error (OpLoc, MultLab);    /* Multiple labels */
  480.         } else {
  481.         while ((x >= OpCode) &&    (*x == ':'))
  482.             *x-- = '\0';
  483.         strcpy (Label, OpCode);    /* Get the label */
  484.         }
  485.         OpLoc = 0;            /* Try again for opcode    */
  486.         OpCode[0] =    '\0';
  487.     }
  488.     }
  489.     for    (x = OpCode; *x; x++)        /* Convert OpCode */
  490.     *x = toupper(*x);        /*  to upper case */
  491.     x -= 2;
  492.     if ((x < OpCode) ||    (*x != '.'))    /* If no explicit size is given */
  493.     Size = Word;            /*  default to Word (16    bits).    */
  494.     else {
  495.     *x++ = '\0';                    /* Chop off size extension */
  496.     switch (*x) {
  497.     case 'B':                       /* Byte */
  498.     case 'S':                       /* Short Branch */
  499.         Size = Byte;
  500.         break;
  501.     case 'L':                       /* Long */
  502.         Size = Long;
  503.         break;
  504.     default:
  505.         Size = Word;        /* Default to Word */
  506.         break;
  507.     }
  508.     }
  509.     while (isspace(*s))
  510.     s++;                /* Skip    over to    operands */
  511.     if ((*s == ';') || (*s == '\0'))
  512.     return;                /* There are no    operands */
  513.     SrcLoc = s - Line;
  514.     s =    GetField (s, SrcOp);        /* Op1 (source)    */
  515.     if (*s == ',')
  516.     s++;
  517.     if (!isspace (*s) && (*s !=    '\0') && (*s != ';')) {
  518.     DestLoc    = s - Line;
  519.     s = GetField (s, DestOp);    /* Op2 (destination) */
  520.     }
  521. }
  522.  
  523.  
  524.  
  525. ShowFile (newline) int newline;
  526. /* Shows the current file name if we're displaying all input modules.
  527.     If "newline" is TRUE, go to a new line before displaying the name. */
  528. {
  529.     if ((Quiet < 0) && (InF->UPtr == 0))
  530.     if (newline)
  531.         fprintf (stderr, "\n%s line ", InF->NPtr);
  532.     else
  533.         fprintf (stderr, "%s line ", InF->NPtr);
  534. }
  535.  
  536.  
  537.  
  538. ShowLine (i) register int i;
  539. /* Shows the current line number and backs up over it. */
  540. {
  541.     if (i >= 10000)
  542.     fprintf    (stderr, "%5d\b\b\b\b\b", i);
  543.     else if (i >= 1000)
  544.     fprintf    (stderr, "%4d\b\b\b\b", i);
  545.     else if (i >= 100)
  546.     fprintf    (stderr, "%3d\b\b\b", i);
  547.     else if (i >= 10)
  548.     fprintf    (stderr, "%2d\b\b", i);
  549.     else
  550.     fprintf    (stderr, "%1d\b", i);
  551.     fflush (stderr);        /* Make    sure it    gets out */
  552. }
  553.  
  554.  
  555.  
  556. char *GetField (s, d) register char *s,    *d;
  557. /* Gets    a field    from "s", returns result in "d".
  558.     Stops on the first comma, semicolon, or white space    not
  559.     enclosed within    apostrophes or parentheses.
  560.     Returns stopping location.
  561.     If already at end of "s", "d" is set to null string. */
  562. {
  563.     register char c;
  564.     register int parncnt, instring;
  565.  
  566.     instring = FALSE;
  567.     parncnt = 0;
  568.  
  569.     while (c = *s) {
  570.     if (instring) {
  571.         *d++ = c;
  572.     } else {
  573.         if (isspace(c) || (c == ';'))
  574.         break;
  575.         else if ((c    == ',') && (parncnt == 0))
  576.         break;
  577.         else {
  578.         *d++ = c;
  579.         if (c == '(')
  580.             parncnt++;
  581.         else if    (c == ')')
  582.             parncnt--;
  583.         }
  584.     }
  585.     if (c == '\'')
  586.         instring = !instring;
  587.     s++;
  588.     }
  589.     *d = '\0';
  590.     return (s);
  591. }
  592.  
  593.  
  594.  
  595. long GetValue (operand,    loc) char *operand; int    loc;
  596. /* Determines value of expression */
  597. /* Hunk2 is set    to hunk    number of result (ABSHUNK if absolute).
  598.    If the expression consists solely of    self-defining terms,
  599.     DefLine2 is set    to zero.  Otherwise, DefLine2 is set
  600.     to the highest statement number    in which any symbol in
  601.     the expression was defined.  If    the expression contains
  602.     any undefined symbols, DefLine2    is set to NODEF.
  603.     The    following code is based    on a regular-to-Polish expression
  604.     converter described in "A Guide to FORTRAN IV Programming"
  605.     by Daniel D. McCracken (John Wiley & Sons, Inc.    1965,
  606.     3rd printing August 1968).  However, rather than generating
  607.     the entire Polish expression, this routine will    evaluate
  608.     and combine two    terms as soon as an operator of    lower
  609.     precedence is encountered.                */
  610. {
  611.     register char *o, *s;
  612.     char tempop[MAXLINE];
  613.     int     oloc, parncnt,    nextprec, instring;
  614.     long templong;
  615.     struct TermStack *origterm;
  616.  
  617.     instring = (unsigned int) '~';
  618.     OpPrec[instring] = 9;    /* Fudge IsOperator for    speed */
  619.     nextprec = TRUE;        /* Assume there's only a single term */
  620.     for    (o = operand; *o; o++) {
  621.     if (IsOperator (o)) {
  622.         nextprec = FALSE;    /* It's not a single term */
  623.         break;
  624.     }
  625.     }
  626.     instring = (unsigned int) '~';
  627.     OpPrec[instring] = '\0';    /* Restore IsOperator */
  628.     if (nextprec)
  629.     return(CalcValue(operand,loc));    /* Short cut for single    term */
  630.  
  631.     Hunk2 = ABSHUNK;
  632.     parncnt = DefLine2 = 0;
  633.     o =    (char *) (((long) NextFNS + 3L)    & ~3L);
  634.     origterm = Term = (struct TermStack    *) o;    /* Term    stack */
  635.     Ops    = (struct OpStack *) InF;        /* Operator stack */
  636.     Ops--;
  637.     ParseSpace (0);
  638.     Ops->chr = ' ';     /* Prime the operator stack */
  639.     Ops->prec =    -1;
  640.     if ((char *) Ops < Low2)
  641.     Low2 = (char *)    Ops;
  642.  
  643.     /* Get all tokens.
  644.     Terms are evaluated, and operator precedence is    determined.
  645.     Left and right parentheses are given a precedence of
  646.         1 and 2 respectively.
  647.     Binary operators are given precedence values starting at 3.
  648.     Unary plus is ignored.
  649.     Unary minus is converted to zero minus the remainder of
  650.         of the expression -    its precedence is set to 9 to
  651.         ensure that    the simulated unary operator is    evaluated
  652.         before the remainder of the    expression.
  653.     Logical    not (~), being another unary operator, is converted
  654.         to -1 exclusive-ORed with the remainder of the expression.
  655.         Its    precedence is also set to 9.                */
  656.  
  657.     o =    operand;            /* Current position in operand */
  658.  
  659.     while (1) {
  660.     while (*o == '(') {             /* Left parenthesis */
  661.         Ops--;
  662.         ParseSpace (0);
  663.         Ops->chr  =    '(';
  664.         Ops->prec =    1;
  665.         if ((char *) Ops < Low2)
  666.         Low2 = (char *)    Ops;
  667.         parncnt++;
  668.         o++;
  669.     }
  670.     if ((*o    == '+') || (*o == '-') || (*o == '~')) {    /* Unary op */
  671.         if (*o != '+') {    /* Ignore unary plus */
  672.         Ops--;
  673.         ParseSpace (sizeof (struct TermStack));
  674.         Term->value   =    (*o == '-') ? 0 : -1;   /* Dummy value */
  675.         Term->hunk    =    ABSHUNK;
  676.         Term->oploc   =    loc + (o - operand);
  677.         Term->defline =    0;
  678.         Term++;
  679.         if ((char *) Term > High2)
  680.             High2 = (char *) Term;
  681.         Ops->chr  = *o;        /* Now get the operator    itself */
  682.         Ops->prec = 9;        /* Do it ASAP */
  683.         if ((char *) Ops < Low2)
  684.             Low2 = (char *) Ops;
  685.         }
  686.         o++;
  687.         if (*o == '(')
  688.         continue;    /* Inner parenthesized expression */
  689.     }
  690.     oloc = loc + (o    - operand);
  691.  
  692.     s = tempop;                /* Get a term */
  693.     if (*o == '*') {        /* It's a location counter reference, */
  694.         *s++ = *o++;    /*   not a multiplication operator!   */
  695.     } else {
  696.         if (IsOperator (o) || (*o == '\0')) {
  697.         Error (oloc, OperErr);    /* Unexpected operator or no terms */
  698.         return (0L);
  699.         }
  700.         instring = (unsigned int) '~';
  701.         OpPrec[instring] = 9;    /* Fudge IsOperator for    speed */
  702.         instring = FALSE;
  703.         while (*o) {
  704.         if (*o == '\'')
  705.             instring=!instring;    /* String delimiter */
  706.         if (!instring && IsOperator (o))
  707.             break;        /* Found an operator - stop */
  708.         *s++ = *o++;        /* Get a character */
  709.         }
  710.         instring = (unsigned int) '~';
  711.         OpPrec[instring] = '\0';    /* Restore IsOperator */
  712.     }
  713.     *s = '\0';
  714.     ParseSpace (sizeof (struct TermStack));
  715.     Term->value   =    CalcValue (tempop, oloc);
  716.     Term->hunk    =    Hunk2;
  717.     Term->oploc   =    oloc;
  718.     Term->defline =    DefLine2;
  719.     Term++;
  720.     if ((char *) Term > High2)
  721.         High2 = (char *) Term;
  722.     Hunk2 =    DefLine2 = 0;
  723.  
  724.     while (*o == ')') {                     /* Right parenthesis */
  725.         if (parncnt    == 0) {
  726.         Error ((int) (loc + (o - operand)), OperErr);
  727.         return (0L);
  728.         }
  729.         CondCalc (2);        /* Unstack what    we can */
  730.         if (Ops->chr == '(')
  731.         Ops++;            /* Drop    paired parentheses */
  732.         else {
  733.         Ops--;
  734.         ParseSpace (0);
  735.         Ops->chr  = ')';        /* Stack parenthesis for now */
  736.         Ops->prec = 2;
  737.         if ((char *) Ops < Low2)
  738.             Low2 = (char *) Ops;
  739.         }
  740.         parncnt--;
  741.         o++;
  742.     }
  743.     if (*o)    {
  744.         nextprec = IsOperator (o);
  745.         if ((nextprec == 0)    || (*o == '(')) {
  746.         Error ((int) (loc + (o - operand)), OperErr);
  747.         return (0L);        /* Expected an operator    */
  748.         }
  749.         CondCalc (nextprec);    /* Unstack what    we can */
  750.         Ops--;
  751.         ParseSpace (0);
  752.         Ops->chr  =    *o;        /* Stack the next operator */
  753.         Ops->prec =    nextprec;
  754.         if ((char *) Ops < Low2)
  755.         Low2 = (char *)    Ops;
  756.         if ((*o == '<') || (*o == '>'))
  757.         o++;    /* Skip    over two-character operator */
  758.         o++;
  759.     } else {
  760.         if (parncnt) {
  761.         Error ((int) (loc + (o - operand)), OperErr);
  762.         return (0L);    /* Too many left parentheses */
  763.         }
  764.         CondCalc (0);        /* Unstack what's left */
  765.         if (--Term != origterm)    /* Should be only one term left    */
  766.         Error (Term->oploc, OperErr);        /* Parser bug? */
  767.         Hunk2    = Term->hunk;
  768.         DefLine2 = Term->defline;
  769.         return (Term->value);    /* Final value */
  770.     }
  771.     }
  772. }
  773.  
  774.  
  775.  
  776. CondCalc (newprec) int newprec;
  777. /* As long as the top operator on the operator stack has a precedence
  778.     greater than or equal to the contents of "newprec", this routine
  779.     will pop the two top terms from the    term stack, combine them
  780.     according to the operator on the top of the    operator stack (which
  781.     is also popped), and push the result back onto the term stack. */
  782. {
  783.     while (Ops->prec >=    newprec) {    /* Unstack an operator */
  784.     Term -=    2;
  785.     if (Ops->chr ==    '+') {          /* Relocatable addition */
  786.         if (Term->hunk == ABSHUNK)
  787.         Term->hunk = (Term+1)->hunk;    /* A+R */
  788.         else if ((Term+1)->hunk != ABSHUNK)    {
  789.         Error ((Term+1)->oploc,    RelErr);    /* R+R - error */
  790.         Term->hunk = ABSHUNK;        /* Make    it absolute */
  791.         }
  792.     } else if (Ops->chr == '-') {           /* Subtraction */
  793.         if (Term->hunk == (Term+1)->hunk)
  794.         Term->hunk = ABSHUNK;        /* R-R - absolute */
  795.         else if ((Term+1)->hunk != ABSHUNK)    {   /* R-R across hunks    */
  796.         Error ((Term+1)->oploc,    RelErr);    /*    is an error -    */
  797.         Term->hunk = ABSHUNK;            /* make it absolute    */
  798.         }
  799.     } else if ((Term->hunk != ABSHUNK)
  800.     || ((Term+1)->hunk != ABSHUNK))    {
  801.         Error (Term->oploc,RelErr);        /* All other operations    */
  802.         Term->hunk = ABSHUNK;        /*   must be absolute    */
  803.     }
  804.     if ((Term+1)->defline >    Term->defline)    /* Definition */
  805.         Term->defline = (Term+1)->defline;    /*  line nos. */
  806.  
  807.     switch (Ops->chr) {        /* Perform the operation */
  808.     case '+':
  809.         Term->value    += (Term+1)->value;
  810.         break;
  811.     case '-':
  812.         Term->value    -= (Term+1)->value;
  813.         break;
  814.     case '*':
  815.         Term->value    *= (Term+1)->value;
  816.         break;
  817.     case '/':
  818.         if ((Term+1)->value)
  819.         Term->value /= (Term+1)->value;
  820.         else
  821.         Term->value = 0;     /*    Don't divide by zero */
  822.         break;
  823.     case '&':
  824.         Term->value    &= (Term+1)->value;
  825.         break;
  826.     case '!':
  827.     case '|':
  828.         Term->value    |= (Term+1)->value;
  829.         break;
  830.     case '<':
  831.         Term->value    <<= (Term+1)->value;
  832.         break;
  833.     case '>':
  834.         Term->value    >>= (Term+1)->value;
  835.         break;
  836.     case '~':
  837.         Term->value    ^= (Term+1)->value;
  838.         break;
  839.     default:
  840.         Error (Term->oploc,    OperErr);    /* Parser bug? */
  841.         break;
  842.     }
  843.     Term++;
  844.     Ops++;
  845.     }
  846. }
  847.  
  848.  
  849.  
  850. int IsOperator (o) register char *o;
  851. /* Tests whether "o" points to a valid operator or parenthesis.
  852.     Returns the    precedence of the operator, or 0 if it isn't one. */
  853. {
  854.     register unsigned int i;
  855.  
  856.     i =    (unsigned int) *o;
  857.     i =    (unsigned int) OpPrec[i];
  858.     if (i != 6)
  859.     return ((int) i);
  860.     if (*(o+1) == *o)
  861.     return ((int) i);    /* << or >> */
  862.     else
  863.     return (0);        /* False alarm */
  864. }
  865.  
  866.  
  867.  
  868. long CalcValue (operand, loc) char *operand; int loc;
  869. /* Evaluates a single term (called by GetValue).
  870.     Hunk2 receives relative hunk number    (ABSHUNK if absolute).
  871.     If the value is a symbol, DefLine2 is set to the line number
  872.     where it was defined, or NODEF if it is    undefined.
  873.     For self-defining terms, DefLine2 is set to zero.    */
  874. {
  875.     register long result;    /* Result is calculated    here */
  876.     register char *s, *numstart;
  877.     register int  radix;
  878.     int     neg, overflow;
  879.     char maxdig;    /* Highest valid digit in current radix    */
  880.     char delim;        /* String delimiter (' or ") */
  881.  
  882.     Hunk2 = ABSHUNK;            /* Assume value    is absolute */
  883.     DefLine2 = 0;            /* and self-defining */
  884.     result = 0;
  885.     overflow = FALSE;
  886.     if (neg = (*operand    == '-'))
  887.     numstart = operand + 1;        /* Negative value */
  888.     else
  889.     numstart = operand;        /* Positive value */
  890.  
  891.     if ((*numstart >= '0') && (*numstart <= '9')) {
  892.     radix =    10;        /* Decimal number */
  893.     maxdig = '9';
  894.     } else if (*numstart == '$') {
  895.     radix =    16;        /* Hexadecimal number */
  896.     maxdig = '9';
  897.     } else if (*numstart == '@') {
  898.     radix =    8;        /* Octal number    */
  899.     maxdig = '7';
  900.     } else if (*numstart == '%') {
  901.     radix =    2;        /* Binary number */
  902.     maxdig = '1';
  903.     } else
  904.     radix =    0;        /* Not a number    */
  905.  
  906.     if (radix != 0) {            /* Some    sort of    number */
  907.     result = 0;
  908.     if (radix != 10)
  909.         numstart++;            /* Allow for type character */
  910.     for (s = numstart; *s; s++) {
  911.         result *= radix;
  912.         if ((*s >= '0') && (*s <= maxdig)) {
  913.         result += (*s -    '0');
  914.         } else if (radix ==    16) {
  915.         if ((*s    >= 'A') && (*s <= 'F'))
  916.             result += (*s - 'A' + 10);
  917.         else if    ((*s >=    'a') && (*s <= 'f'))
  918.             result += (*s - 'a' + 10);
  919.         else
  920.             Error (loc + s - operand, OperErr);
  921.         } else if (!neg && (radix==10) && (*s=='$') && (*(s+1)=='\0')) {
  922.         if (ReadSymTab (operand)) {    /* Look    up local label */
  923.             result = Value;        /* Get its value */
  924.             AddRef (LineCount);        /* Add reference */
  925.             if (Sym->Flags & 0x60)
  926.             Error (loc, AddrErr);    /* Can't use a register equate */
  927.         } else {
  928.             Error (loc,    Undef);        /* Undefined */
  929.         }
  930.         break;
  931.         } else {
  932.         Error (loc + s - operand, OperErr);
  933.         }
  934.     }
  935.     } else if ((*operand == '\'') || (*operand == '"')) {
  936.     delim =    *operand;        /* Character value delimiter */
  937.     result = 0;
  938.     s = operand + 1;
  939.     while (1) {
  940.         if (*s == '\0') {
  941.         Error (loc+s-operand,NoStrEnd);    /* End is missing */
  942.         result = 0;
  943.         break;
  944.         }
  945.         if (*s == delim) {        /* End of string? */
  946.         if (*(++s) != delim)    /* Check next character    */
  947.             break;        /* End of string */
  948.         }        /* Otherwise it's an apostrophe in the string */
  949.         if ((result    & 0xFF000000L) && !overflow) {
  950.         Error (loc+s-operand, SizeErr);    /* Result overflowed */
  951.         overflow = TRUE;
  952.         result = 0;
  953.         }
  954.         if (!overflow)
  955.         result = (result << 8) + *s;
  956.         s++;
  957.     }
  958.     } else if ((*operand == '*') && (*(operand+1) == '\0')) {
  959.     result = AddrCnt;    /* Value of location counter */
  960.     Hunk2 =    CurrHunk;    /* Use current section's hunk number */
  961.     } else {
  962.     if (ReadSymTab (operand)) {    /* Look    up symbol */
  963.         result = Value;        /* Get its value */
  964.         AddRef (LineCount);        /* Add reference */
  965.         if (Sym->Flags & 0x60)
  966.         Error (loc, AddrErr);    /* Can't use a register equate */
  967.     } else if (strcmp (operand, "NARG") == 0) {
  968.         result = InF->NArg;        /* Number of arguments */
  969.         if (result == -1)
  970.         result = 0;        /* No arguments    outside    macros */
  971.     } else
  972.         Error (loc,    Undef);        /* Undefined */
  973.     }
  974.     if (neg) {
  975.     result = -result;        /* Negative value */
  976.     if (Hunk2 != ABSHUNK)
  977.         Error (loc,    RelErr);    /* Must    be absolute */
  978.     }
  979.     return (result);
  980. }
  981.  
  982.  
  983.  
  984. AddSymTab (label, value, hunk, line, flags)
  985. char label[];
  986. long value, hunk;
  987. int line, flags;
  988. /* Inserts a new entry to the symbol table and increments NumSyms.
  989.     "Sym" will be set to point to the new entry.
  990.     If the label is a local label (i.e.    the first character is
  991.     a numeric digit or a backslash), the current contents of LabLine
  992.     will be converted to characters and    appended to the    label before
  993.     it is added.  If the first character of the    label is a backslash
  994.     (i.e. a named local    variable) a dollar sign    will be    appended
  995.     to the label ahead of the value of LabLine.            */
  996. {
  997.     char wlab[MAXLINE],    wnum[6];
  998.     register struct SymTab *chainsym, **hashindex;
  999.  
  1000.     strcpy (wlab, label);
  1001.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  1002.     if (label[0] ==    '\\')
  1003.         strcat (wlab, "$");
  1004.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  1005.     strcat (wlab, wnum);        /*    append LabLine      */
  1006.     }
  1007.  
  1008.     Sym    = SymLim;            /* Pointer to new entry    */
  1009.     SymLim++;                /* Bump    limit pointer */
  1010.     if (((char *) SymLim - (char *) SymCurr) > CHUNKSIZE) {
  1011.     Sym = (struct SymTab *)    malloc ((unsigned) CHUNKSIZE);
  1012.     if (Sym    == NULL)
  1013.         quit_cleanup ("Out of memory!\n");
  1014.     SymCurr->Link =    Sym;        /* Link    from previous chunk */
  1015.     SymCurr    = Sym;            /* Make    the new    chunk current */
  1016.     SymCurr->Link =    NULL;        /* Clear forward pointer */
  1017.     Sym++;                /* Skip    over pointer entry */
  1018.     SymLim = Sym;            /* New table limit */
  1019.     SymLim++;            /* Bump    it */
  1020.     }
  1021.     Sym->Link =    NULL;        /* Clear hash chain link */
  1022.     Sym->Nam = AddName(wlab,0);    /* Pointer to symbol */
  1023.     Sym->Val   = value;        /* Value */
  1024.     Sym->Hunk  = hunk;        /* Hunk    number */
  1025.     Sym->Defn  = line;        /* Statement number */
  1026.     Sym->Flags = flags;        /* Flags */
  1027.     Sym->Ref1  = NULL;        /* Reference pointer */
  1028.     NumSyms++;            /* Count symbols */
  1029.  
  1030.     hashindex =    HashIt (wlab);    /* Get hash index */
  1031.     if (*hashindex == NULL) {
  1032.     *hashindex = Sym;    /* First entry in this hash chain */
  1033.     return;
  1034.     }
  1035.     chainsym = *hashindex;
  1036.     while (chainsym->Link != NULL)
  1037.     chainsym = chainsym->Link;    /* Scan    for end    of hash    chain */
  1038.     chainsym->Link = Sym;        /* Insert new entry at the end */
  1039. }
  1040.  
  1041.  
  1042.  
  1043. char *AddName (name, macflag) char *name; int macflag;
  1044. /* Adds    the name in "name" to the name heap.
  1045.     "macflag" can take any of the following values:
  1046.     0 - normal name
  1047.     1 - first line of macro    text - there must be room on the
  1048.         name heap for at least one character following "name".
  1049.     2 - additional lines of    macro text - make sure there's room
  1050.         for an addition    character (as in 1 above).  Also,
  1051.         if it is necessary to allocate a new chunk of memory,
  1052.         first place a newline character    after the last entry
  1053.         in the old chunk.  This    acts as    a flag when retrieving
  1054.         lines of macro text during an expansion.
  1055.     This function returns a pointer to "name" on the name heap. */
  1056. {
  1057.     register char *s, *t;
  1058.     struct NameChunk *n;
  1059.  
  1060.     s =    NameLim    + strlen(name) + 1;    /* The new entry ends here */
  1061.     if (macflag)            /* If this is a    macro, */
  1062.     s++;                /*  allow for continuation flag. */
  1063.     if ((s - (char *) NameCurr)    > CHUNKSIZE) {    /* If this chunk is full */
  1064.     if (macflag == 2)        /* If this is more macro text */
  1065.         *NameLim = '\n';            /*  insert continuation flag. */
  1066.     n = (struct NameChunk *) malloc    ((unsigned) CHUNKSIZE);
  1067.     if (n == NULL)
  1068.         quit_cleanup ("Out of memory!\n");
  1069.     NameCurr->Link = n;        /* Link    from previous chunk */
  1070.     NameCurr = n;            /* Make    the new    chunk current */
  1071.     NameCurr->Link = NULL;        /* Clear forward pointer */
  1072.     s = (char *) NameCurr;
  1073.     NameLim    = s + sizeof (char *);    /* Skip    over pointer entry */
  1074.     }
  1075.     s =    NameLim;
  1076.     t =    name;
  1077.     while ((*s++ = *t++) != '\0')       /* Store name */
  1078.     ;
  1079.     t =    NameLim;
  1080.     NameLim = s;            /* Update table    limit */
  1081.     return (t);
  1082. }
  1083.  
  1084.  
  1085.  
  1086. int ReadSymTab (label) char label[];
  1087. /* Searches the    symbol table for the given label.
  1088.    If not found, points    Sym to NULL and    returns    FALSE.
  1089.    If found, points Sym    to the proper table entry,
  1090.      and sets up the following fields:
  1091.     Value     - value of symbol
  1092.     Hunk2     - hunk    number in which    symbol resides
  1093.            ABSHUNK if value is absolute
  1094.            ones    complement of symbol table index if external
  1095.     DefLine2 - statement number in which symbol was    defined
  1096.             (NODEF if undefined )
  1097.     If the label is a local label (i.e.    the first character is
  1098.     numeric), the current contents of LabLine will be converted
  1099.     to characters and appended to the label before it is searched.
  1100.     (This matches the way AddSymTab added the label to the table.)
  1101.     If the first character of the label    is a backslash (i.e. a
  1102.     named local    variable) a dollar sign    will be    appended to the
  1103.     label ahead    of the value of    LabLine.            */
  1104. {
  1105.     char wlab[MAXLINE],    wnum[6];
  1106.     register struct SymTab **hashindex;
  1107.  
  1108.     strcpy (wlab, label);
  1109.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  1110.     if (label[0] ==    '\\')
  1111.         strcat (wlab, "$");
  1112.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  1113.     strcat (wlab, wnum);        /*    append LabLine      */
  1114.     }
  1115.     hashindex =    HashIt (wlab);    /* Get hash index */
  1116.     Sym    = *hashindex;
  1117.     while (Sym != NULL)    {
  1118.     if (strcmp (Sym->Nam, wlab) == 0) {
  1119.         Value = Sym->Val;        /* Found it */
  1120.         Hunk2 = Sym->Hunk;
  1121.         if (!(Sym->Flags & 9))
  1122.         Hunk2 &= 0x0000FFFFL;    /* Isolate hunk    number */
  1123.         DefLine2 = Sym->Defn;
  1124.         return (TRUE);
  1125.     }
  1126.     Sym = Sym->Link;
  1127.     }
  1128.     Value = 0;            /* Didn't find it - */
  1129.     Hunk2 = ABSHUNK;        /* set value to    absolute zero */
  1130.     DefLine2 = NODEF;
  1131.     return (FALSE);
  1132. }
  1133.  
  1134.  
  1135.  
  1136. struct SymTab **HashIt (label) register    char *label;
  1137. /* Returns a pointer to    the hash table entry corresponding to "label" */
  1138. {
  1139.     register unsigned i;
  1140.  
  1141.     i =    0;
  1142.     while (*label) {
  1143.     i = ((i    << 3) -    i + *label++) %    HashSize;
  1144.     }
  1145.     return (Hash + i);
  1146. }
  1147.  
  1148.  
  1149.  
  1150. struct SymTab *NextSym (sym) register struct SymTab *sym;
  1151. /* Returns a pointer to    the next symbol    table entry in memory,
  1152.     or NULL if there are no more symbol    table entries.
  1153.     SymChunk and SymChLim must be properly set up.    */
  1154. {
  1155.     register struct SymTab *sp;
  1156.  
  1157.     if (sym == NULL)
  1158.     return (NULL);        /* We're nowhere - get out */
  1159.     sym++;
  1160.     sp = sym;
  1161.     sp++;
  1162.     if ((SymLim    >= SymChunk) &&    (SymLim    <= SymChLim))
  1163.     if (sym    >= SymLim)
  1164.         return (NULL);    /* End of symbol table entries */
  1165.     if (sp > SymChLim) {
  1166.     if ((SymChunk =    SymChunk->Link)    == NULL)
  1167.         return (NULL);    /* End of the last chunk */
  1168.     SymChLim = (struct SymTab *) ((char *) SymChunk    + CHUNKSIZE);
  1169.     sym = SymChunk;
  1170.     sym++;            /* First entry in the new chunk    */
  1171.     }
  1172.     return (sym);
  1173. }
  1174.  
  1175.  
  1176.  
  1177. AddRef (linenum) int linenum;
  1178. /* Adds    "linenum" to the list of references
  1179.     for    the symbol pointed to by Sym.        */
  1180. {
  1181.     register int i;
  1182.     register struct Ref    *ref, *prevref;
  1183.  
  1184.     if (!Pass2)
  1185.     return;            /* Pass    2 only!    */
  1186.     if (!XrefList)
  1187.     return;            /* No cross-reference */
  1188.     prevref = NULL;
  1189.     ref    = Sym->Ref1;
  1190.     while (ref)    {        /* Chase pointers */
  1191.     for (i = 0; i <    MAXREF;    i++) {        /* Scan reference entry */
  1192.         if (ref->RefNum[i] == 0) {        /*    for an empty slot   */
  1193.         ref->RefNum[i] = linenum;   /* Insert new line number */
  1194.         return;
  1195.         }
  1196.     }
  1197.     prevref    = ref;            /* Remember where we were */
  1198.     ref = ref->NextRef;        /* Link    to the next entry */
  1199.     }
  1200.     ref    = RefLim;            /* Pointer to new entry    */
  1201.     RefLim++;                /* Bump    limit pointer */
  1202.     if (((char *) RefLim - (char *) SymCurr) > CHUNKSIZE) {
  1203.     ref = (struct Ref *) malloc ((unsigned)    CHUNKSIZE);
  1204.     if (ref    == NULL) {
  1205.         fprintf (stderr, "     \nOut of memory");
  1206.         fprintf (stderr, " - cross-reference disabled.\n");
  1207.         XrefList = FALSE;
  1208.         return;
  1209.     }
  1210.     SymCurr->Link =    (struct    SymTab *) ref;    /* Link    from prev. chunk */
  1211.     SymCurr    = (struct SymTab *)ref;    /* Make    the new    chunk current */
  1212.     SymCurr->Link =    NULL;        /* Clear forward pointer */
  1213.     ref++;                /* Skip    over pointer entry */
  1214.     RefLim = ref;            /* New table limit */
  1215.     RefLim++;            /* Bump    it */
  1216.     }
  1217.     ref->NextRef = NULL;        /* Pointer to next entry */
  1218.     ref->RefNum[0] = linenum;        /* First reference in new entry    */
  1219.     for    (i = 1;    i < MAXREF; i++)
  1220.     ref->RefNum[i] = 0;        /* Clear remaining slots */
  1221.     if (prevref    == NULL)
  1222.     Sym->Ref1 = ref;        /* Link    to first entry */
  1223.     else
  1224.     prevref->NextRef = ref;        /* Link    to next    entry */
  1225. }
  1226.  
  1227.  
  1228.  
  1229. int CountNest (s) register char    *s;
  1230. /* Returns 1 if    "s" contains any IF statement (i.e. IFEQ, etc.).
  1231.    Returns -1 if "s" contains "ENDC" or "ENDIF".
  1232.    Returns 0 in    all other cases.        */
  1233. {
  1234.    if (strcmp (s, "ENDC") == 0)
  1235.        return (-1);
  1236.    else    if (strcmp (s, "ENDIF") == 0)
  1237.        return (-1);
  1238.    else    if (*s++ != 'I')
  1239.     return (0);
  1240.    else    if (*s++ != 'F')
  1241.     return (0);
  1242.    else    if (strcmp (s, "EQ") == 0)
  1243.        return (1);
  1244.    else    if (strcmp (s, "NE") == 0)
  1245.        return (1);
  1246.    else    if (strcmp (s, "GT") == 0)
  1247.        return (1);
  1248.    else    if (strcmp (s, "GE") == 0)
  1249.        return (1);
  1250.    else    if (strcmp (s, "LT") == 0)
  1251.        return (1);
  1252.    else    if (strcmp (s, "LE") == 0)
  1253.        return (1);
  1254.    else    if (strcmp (s, "C" ) == 0)
  1255.        return (1);
  1256.    else    if (strcmp (s, "NC") == 0)
  1257.        return (1);
  1258.    else    if (strcmp (s, "D" ) == 0)
  1259.        return (1);
  1260.    else    if (strcmp (s, "ND") == 0)
  1261.        return (1);
  1262.    else
  1263.        return (0);
  1264. }
  1265.  
  1266.  
  1267.  
  1268. Heap2Space (n) int n;
  1269. /* Die if we can't find "n" bytes on the secondary heap. */
  1270. {
  1271.     if ((NextFNS + n) >    (char *) InF) {
  1272.     printf ("\n%5d   %s\n", LineCount, Line);
  1273.     quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
  1274.     }
  1275. }
  1276.  
  1277.  
  1278.  
  1279. ParseSpace (n) int n;
  1280. /* Special version of Heap2Space for the expression parser */
  1281. {
  1282.     if (((char *) Term + n) > (char *) Ops) {
  1283.     printf ("\n%5d   %s\n", LineCount, Line);
  1284.     quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
  1285.     }
  1286. }
  1287. SHAR_EOF
  1288. cat << \SHAR_EOF > Operands.c
  1289. /*------------------------------------------------------------------*/
  1290. /*                                    */
  1291. /*              MC68000 Cross Assembler                */
  1292. /*                                    */
  1293. /*          Copyright    (c) 1985 by Brian R. Anderson            */
  1294. /*                                    */
  1295. /*        Operand    processor - January 10,    1989            */
  1296. /*                                    */
  1297. /*   This program may be copied    for personal, non-commercial use    */
  1298. /*   only, provided that the above copyright notice is included        */
  1299. /*   on    all copies of the source code.    Copying    for any    other use   */
  1300. /*   without the consent of the    author is prohibited.            */
  1301. /*                                    */
  1302. /*------------------------------------------------------------------*/
  1303. /*                                    */
  1304. /*        Originally published (in Modula-2) in            */
  1305. /*        Dr.    Dobb's Journal, April, May, and June 1986.          */
  1306. /*                                    */
  1307. /*     AmigaDOS conversion copyright 1989 by Charlie Gibbs.        */
  1308. /*                                    */
  1309. /*------------------------------------------------------------------*/
  1310.  
  1311. #include <stdio.h>
  1312. #include "a68kdef.h"
  1313. #include "a68kglb.h"
  1314.  
  1315. /* Functions */
  1316. extern int  LineParts(), Instructions(), ObjDir();
  1317. extern int  ReadSymTab(), OpenIncl(), CountNest();
  1318. extern long AddrBndW(),    AddrBndL(), GetValue(),    CalcValue();
  1319. extern char *AddName(),    *GetField();
  1320. extern struct SymTab *NextSym();
  1321. extern struct SymTab **HashIt();
  1322.  
  1323. int GetArgs(), GetAReg(), GetInstModeSize(), GetMultReg();
  1324.  
  1325.  
  1326.  
  1327. int GetArgs (name) char    *name;
  1328. /* Gets    macro arguments    and adds them to FNStack after adding "name".
  1329.     Returns the    number of arguments added to the stack.
  1330.     Note that this might not be    the full number    of arguments
  1331.     provided if    the stack overflowed.                */
  1332. {
  1333.     register char *s, *t;
  1334.     int    narg, instring;
  1335.     char currarg[MAXLINE];        /* Current argument */
  1336.  
  1337.     narg = strlen (name) + 1;
  1338.     Heap2Space (narg);            /* Find    space for name */
  1339.     strcpy (NextFNS, name);        /* Add name to stack */
  1340.     NextFNS += narg;            /* Bump    pointer    */
  1341.     if (NextFNS    > High2)
  1342.     High2 =    NextFNS;        /* Update high-water mark */
  1343.  
  1344.     narg = 0;                /* Argument counter */
  1345.  
  1346.     s =    Line + SrcLoc;            /* Now scan Line */
  1347.     while (!isspace(*s)    && (*s != ';') && (*s != '\0')) {
  1348.     t = currarg;
  1349.     if (instring = (*s == '<'))     /* String delimiter */
  1350.         s++;
  1351.     while (1) {
  1352.         if (*s == '\0')
  1353.         break;            /* End of line */
  1354.         if (instring) {
  1355.         if (*s == '>') {
  1356.             s++;
  1357.             break;        /* End of string */
  1358.         }
  1359.         } else {
  1360.         if ((*s    == ',')         /* End of operand */
  1361.         || isspace(*s)        /* End of all operands */
  1362.         || (*s == ';'))         /* Start of comments */
  1363.             break;
  1364.         }
  1365.         *t++ = *s++;        /* Get a character */
  1366.     }
  1367.     *t++ = '\0';
  1368.     Heap2Space (t -    currarg);    /* Check for space */
  1369.     strcpy (NextFNS, currarg);    /* Store argument */
  1370.     NextFNS    += t - currarg;        /* Next    available space    */
  1371.     if (NextFNS > High2)
  1372.         High2 = NextFNS;        /* High-water mark */
  1373.     narg++;                /* Count arguments */
  1374.     if (*s == ',')
  1375.         s++;            /* Skip    over separator */
  1376.     }
  1377.     return (narg);            /* Successful completion */
  1378. }
  1379.  
  1380.  
  1381.  
  1382. EffAdr (EA, Bad) register struct OpConfig *EA; int Bad;
  1383. /* Adds    effective address field    to Op (BITSET representing opcode) */
  1384. {
  1385.     if ((1 << (EA->Mode    - 1)) IN Bad) {
  1386.     Error (EA->Loc,    ModeErr);    /* Invalid mode    */
  1387.     return;
  1388.     } else if (EA->Mode    > 12)        /* Special modes */
  1389.     return;
  1390.     else if (EA->Mode <    8)        /* Register direct or indirect */
  1391.     Op |= ((EA->Mode - 1) << 3) | EA->Rn;
  1392.     else
  1393.     Op |= 0x0038 | (EA->Mode - 8);    /* Absolute modes */
  1394.     OperExt (EA);
  1395. }
  1396.  
  1397.  
  1398.  
  1399. OperExt    (EA) register struct OpConfig *EA;
  1400. /* Calculate operand Extension word, and check range of    operands */
  1401. {
  1402.     switch (EA->Mode) {
  1403.     case AbsL:
  1404.         break;   /*    No range checking needed */
  1405.     case AbsW:
  1406.     case ARDisp:
  1407.     case PCDisp:
  1408.         if ((EA->Value < -32768) ||    (EA->Value > 32767))
  1409.         Error (EA->Loc,    SizeErr);
  1410.         break;
  1411.     case ARDisX:
  1412.     case PCDisX:
  1413.         if ((EA->Value < -128) || (EA->Value > 127))
  1414.         Error (EA->Loc,    SizeErr);
  1415.         EA->Value &= 0x00FF;              /* Displacement */
  1416.         EA->Value |= EA->Xn    << 12;            /* Index reg. */
  1417.         if (EA->X == Areg)       EA->Value |=    0x8000;    /* Addr. Reg. */
  1418.         if (EA->Xsize == Long) EA->Value |=    0x0800;    /* Long    reg.  */
  1419.         break;
  1420.     case Imm:
  1421.         if (Size ==    Word) {
  1422.         if ((EA->Value < -32768) || (EA->Value > 65535L))
  1423.             Error (EA->Loc, SizeErr);
  1424.         } else if (Size == Byte)
  1425.         if ((EA->Value < -128) || (EA->Value > 255))
  1426.             Error (EA->Loc, SizeErr);
  1427.         break;
  1428.     }
  1429. }
  1430.  
  1431.  
  1432.  
  1433. GetOperand (oper, op, pcconv)
  1434. char *oper; register struct OpConfig *op; int pcconv;
  1435. /* Finds mode and value    for source or destination operand.
  1436.     If PC-relative addressing is permitted, "pcconv" gives the
  1437.     offset to the displacement word; otherwise "pcconv" is zero. */
  1438. {
  1439.     register char *s, *t;
  1440.     register int  i;
  1441.     char *opend;
  1442.     char UCoper[MAXLINE], tempop[MAXLINE];
  1443.     int     rloc;
  1444.     long templong;
  1445.  
  1446.     op->Value =    op->Defn = 0;
  1447.     op->Mode = Null;
  1448.     op->X    = X0;
  1449.     op->Hunk = ABSHUNK;
  1450.  
  1451.     if (*oper == '\0')
  1452.     return;                /* Nothing to process */
  1453.  
  1454.     s =    oper;
  1455.     t =    UCoper;
  1456.     while (*t++    = toupper (*s++))    /* Upper-case version */
  1457.     ;
  1458.     opend = s -    2;            /* Last    character of operand */
  1459.  
  1460.     if (*oper == '#') {                 /* Immediate */
  1461.     op->Value = GetValue (oper+1, (op->Loc)+1);
  1462.     op->Mode  = Imm;
  1463.     op->Hunk  = Hunk2;
  1464.     op->Defn  = DefLine2;
  1465.     return;
  1466.     }
  1467.  
  1468.     i =    IsRegister (oper, opend-oper+1);
  1469.     if (i >= 0)    {
  1470.     op->Mode = (i &    8) ? ARDir : DReg;    /* Register type */
  1471.     op->Rn = i & 7;                /* Register number */
  1472.     return;
  1473.     } else if (i == -2)    {
  1474.     op->Mode = MultiM;            /* Equated register list */
  1475.     op->Value = Sym->Val;
  1476.     return;
  1477.     } else if ((*oper == '(') && (*opend == ')')) {
  1478.     i = IsRegister (oper+1,    opend-oper-1);
  1479.     if (i >= 8 && i    <= 15) {
  1480.         op->Mode = ARInd;        /* Address Register indirect */
  1481.         op->Rn = i - 8;
  1482.         return;
  1483.     } else if (i !=    -1) {
  1484.         Error (op->Loc, AddrErr);    /* Data    register is invalid */
  1485.         return;
  1486.     }    /* else    may be parenthesized expression    */
  1487.     } else if ((*oper == '(')           /* Post-increment */
  1488.     && (*opend == '+')
  1489.     && (*(opend-1) == ')')) {
  1490.     op->Mode = ARPost;
  1491.     op->Rn = GetAReg (oper+1, opend-oper-2,    op->Loc    + 1);
  1492.     return;
  1493.     } else if ((*oper == '-')           /* Pre-decrement */
  1494.     && (*opend == ')')
  1495.     && (*(oper+1) == '(')) {
  1496.     i = IsRegister (oper+2,    opend-oper-2);
  1497.     if (i >= 8 && i    <= 15) {
  1498.         op->Mode = ARPre;
  1499.         op->Rn = i - 8;
  1500.         return;
  1501.     } else if (i > 0) {
  1502.         Error (op->Loc, AddrErr);    /* Data    register is invalid */
  1503.         return;
  1504.     }    /* else    parenthesized expression with leading minus? */
  1505.     } else if (strcmp (UCoper, "SR") == 0) {
  1506.     op->Mode = SR;                /* Status Register */
  1507.     return;
  1508.     } else if (strcmp (UCoper, "CCR") == 0) {
  1509.     op->Mode = CCR;            /* Condition Code Register */
  1510.     return;
  1511.     } else if (strcmp (UCoper, "USP") == 0) {
  1512.     op->Mode = USP;            /* User    Stack Pointer */
  1513.     return;
  1514.     }
  1515.  
  1516.     /* Try to split off    displacement (if present).
  1517.     We'll assume we have a register expression if the operand
  1518.     ends with a parenthesized expression not preceded by an
  1519.     operator.  I know this code is a real kludge, but that's
  1520.     the result of the bloody syntax.  Thanks, Motorola.    */
  1521.  
  1522.     s =    opend;                /* Last    character */
  1523.     if (i = (*s    == ')'))                /* Trailing parenthesis? */
  1524.     while (*(--s) != '(')           /* Find left parenthesis */
  1525.         if (s <= oper)
  1526.         break;
  1527.     if (s <= oper)            /* Must    not be at beginning */
  1528.     i = FALSE;
  1529.     if (i) {
  1530.     if (s == (oper+1)) {
  1531.         if (*oper == '-')
  1532.         i = FALSE;        /* Leading minus sign */
  1533.     } else {
  1534.         t =    s - 1;
  1535.         if (*t == '*') {            /* Location counter? */
  1536.         t--;
  1537.         if (!IsOperator    (t) || (*t == ')'))
  1538.             i =    FALSE;        /* No, it's multiplication */
  1539.         } else if (IsOperator (t) && (*t !=    ')')) {
  1540.         i = FALSE;        /* Preceded by an operator */
  1541.         }
  1542.     }
  1543.     }
  1544.  
  1545.     if (i) {        /* Looks like a    displacement mode */
  1546.     *s = '\0';
  1547.     op->Value = GetValue (oper, op->Loc);    /* Displacement    */
  1548.     op->Hunk  = Hunk2;            /* Hunk    number */
  1549.     op->Defn  = DefLine2;            /* Line    where defined */
  1550.     *s++ = '(';                             /* Restore parenthesis */
  1551.  
  1552.     rloc = op->Loc + s - oper;    /* The register    starts here */
  1553.     s = GetField (s, tempop);    /* Get address register    */
  1554.     if (*s == '\0')                 /* If there's no index register */
  1555.         tempop[strlen(tempop)-1] = '\0';    /* chop parenthesis */
  1556.  
  1557.     if ((tempop[2] == '\0')
  1558.     && (toupper (tempop[0])    == 'P')
  1559.     && (toupper (tempop[1])    == 'C')) {
  1560.         op->Mode = PCDisp;            /* Program Counter */
  1561.         if (op->Hunk == CurrHunk) {
  1562.         op->Value -= (AddrCnt+pcconv);    /* Adjust displacement */
  1563.         op->Hunk = ABSHUNK;
  1564.         }
  1565.     } else {
  1566.         if ((op->Value == 0)    /* If displacement is zero   */
  1567.         && (op->Hunk == ABSHUNK)    /*  and    is absolute         */
  1568.         && (op->Defn < LineCount)    /*  and    is already defined   */
  1569.         && !(OpM68R    IN AdrModeA))    /*  and    isn't for a MOVEP    */
  1570.         op->Mode = ARInd;    /*  forget the displacement. */
  1571.         else
  1572.         op->Mode = ARDisp;    /* Address reg.    w/displacement */
  1573.         op->Rn = GetAReg (tempop, strlen (tempop), rloc);
  1574.     }
  1575.     if (*s != '\0') {               /* Index register is present */
  1576.         if (op->Mode == PCDisp)
  1577.         op->Mode = PCDisX;    /* Program Counter indexed */
  1578.         else
  1579.         op->Mode = ARDisX;    /* Address Register indexed */
  1580.         if (*s != ',')
  1581.         Error (op->Loc,    AddrErr);    /* Bad separator */
  1582.         s++;                /* Skip    separator */
  1583.         rloc = op->Loc + s - oper;        /* Start of index */
  1584.         s =    GetField (s, tempop);        /* Get index register */
  1585.         t =    tempop + strlen(tempop);
  1586.         if (*s == '\0')
  1587.         *(--t) = '\0';                  /* Chop parenthesis */
  1588.         else
  1589.         Error (rloc, AddrErr);        /* It better be    there */
  1590.  
  1591.         t -= 2;
  1592.         if ((t < tempop) ||    (*t != '.')) {
  1593.         op->Xsize = Word;    /* Size    defaults to 16 bits */
  1594.         t += 3;
  1595.         } else {
  1596.         *t++ = '\0';                    /* Chop off size code */
  1597.         switch (toupper    (*t)) {
  1598.         case 'W':                       /* Word */
  1599.             op->Xsize =    Word;
  1600.             break;
  1601.         case 'L':                       /* Long */
  1602.             op->Xsize =    Long;
  1603.             break;
  1604.         default:
  1605.             Error (op->Loc+s-1-oper, SizeErr);    /* Invalid size    */
  1606.             op->Xsize =    Word;        /* Make    it word    for now    */
  1607.         }
  1608.         }
  1609.         i =    IsRegister (tempop,t-tempop-1);    /* Get register    */
  1610.         op->Xn = i & 7;            /* Index register number */
  1611.         if ((i >= 0) && (i <= 7))
  1612.         op->X =    Dreg;            /* Data    Register */
  1613.         else if ((i    >= 8) && (i <= 15))
  1614.         op->X =    Areg;            /* Address Register */
  1615.         else
  1616.         Error (rloc, AddrErr);        /* Invalid register */
  1617.     }
  1618.  
  1619.     if ((op->Hunk >= 0) && (op->Hunk != ABSHUNK))
  1620.         Error (op->Loc, RelErr);    /*  Relocatable    displacement */
  1621.     return;
  1622.     }
  1623.  
  1624.     if ((i = GetMultReg    (oper, op->Loc)) != 0) {
  1625.     op->Value = (long) i;
  1626.     op->Mode = MultiM;        /* Register list for MOVEM */
  1627.     return;
  1628.     }
  1629.  
  1630.     op->Value =    GetValue (oper,    op->Loc);    /* Get operand value */
  1631.     op->Hunk  =    Hunk2;
  1632.     op->Defn  =    DefLine2;
  1633.     op->Mode  =    AbsL;        /* Assume absolute long    addressing */
  1634.  
  1635.     if (DefLine2 < LineCount) {        /* Backward reference */
  1636.  
  1637.     if (Hunk2 < 0) {
  1638.         return;        /* External - leave as absolute    long */
  1639.  
  1640.     } else if (Hunk2 == CurrHunk) {    /* Reference to    current    hunk */
  1641.         if (pcconv)    {
  1642.         templong = op->Value-(AddrCnt+pcconv);    /* PC disp. */
  1643.         if ((templong >= -32768) && (templong <= 32767)) {
  1644.             op->Mode = PCDisp;    /* Convert to PC relative mode */
  1645.             op->Value=templong;    /* Adjust displacement */
  1646.             op->Hunk = ABSHUNK;
  1647.         }
  1648.         }
  1649.  
  1650.     } else if (Hunk2 == ABSHUNK) {    /* Absolute value */
  1651.         if ((op->Value >= -32768) && (op->Value <= 32767))
  1652.         op->Mode = AbsW;    /* Absolute word */
  1653.  
  1654.     } else if (SmallData &&    (op->Value>=0) && (op->Value<=65535L)) {
  1655.         op->Mode = ARDisp;        /* Make    it a data reference */
  1656.         op->Rn = 4;            /*  through register A4        */
  1657.         op->Value -= 32768L;    /* Adjust displacement */
  1658.         op->Hunk = ABSHUNK;
  1659.     }
  1660.     return;            /* Could default to absolute long */
  1661.  
  1662.     } else if (!SmallData) {    /* Fwd.    reference - if not small data */
  1663.     return;            /*  leave as absolute long addressing */
  1664.  
  1665.     } else if (!Pass2) {    /* Forward reference, pass 1 */
  1666.     op->Mode = ARDisp;    /* Assume displacement */
  1667.     op->Rn = 4;        /*  from register A4   */
  1668.     op->Hunk = ABSHUNK;
  1669.     return;
  1670.  
  1671.     } else {            /* On pass 2 we    know what it is    */
  1672.  
  1673.     if (Hunk2 < 0) {
  1674.         Error (op->Loc,FwdRef);    /* External - must be 32 bits */
  1675.         op->Mode = AbsW;        /* Force absolute word anyway */
  1676.  
  1677.     } else if (Hunk2 == CurrHunk) {    /* It's in the current hunk */
  1678.         op->Mode = PCDisp;        /* Convert to PC relative mode */
  1679.         op->Value -= AddrCnt + pcconv;    /* Adjust displacement */
  1680.         op->Hunk = ABSHUNK;
  1681.         if (!pcconv    || (op->Value <    -32768)    || (op->Value >    32767))
  1682.         Error (op->Loc,FwdRef);    /* It doesn't fit! */
  1683.  
  1684.     } else if (Hunk2 == ABSHUNK) {    /* It's absolute */
  1685.         op->Mode = AbsW;        /* It has to fit in a word */
  1686.         if ((op->Value < -32768) ||    (op->Value > 32767))
  1687.         Error (op->Loc,FwdRef);    /* It doesn't fit! */
  1688.  
  1689.     } else {
  1690.         op->Mode = ARDisp;        /* Assume data reference */
  1691.         op->Rn = 4;            /*  through register A4     */
  1692.         op->Value -= 32768L;    /* Adjust displacement */
  1693.         if ((op->Value < -32768) ||    (op->Value > 32767))
  1694.         Error (op->Loc,FwdRef);    /* It doesn't fit! */
  1695.     }
  1696.     }
  1697. }
  1698.  
  1699.  
  1700.  
  1701. int GetMultReg (oper, loc) char    *oper; int loc;
  1702. /* Builds a register mask for the MOVEM    instruction.
  1703.     Returns the    mask in    the low-order portion of its value if
  1704.     "oper" is a valid multiple-register list; otherwise returns 0. */
  1705. {
  1706.     register char *s, *t;
  1707.     register int  j;
  1708.     int    t1, t2;        /* Temporary variables for registers */
  1709.     int    range;        /* We're processing a range of registers */
  1710.     int    multext;    /* The result is built here */
  1711.  
  1712.     multext = 0;
  1713.     range = FALSE;
  1714.     s =    oper;
  1715.     if (IsOperator (s))
  1716.     return (0);            /* Starts with an operator! */
  1717.  
  1718.     while (1) {
  1719.     for (t = s; *t;    t++) {
  1720.         if ((*t == '-') || (*t == '/')) {
  1721.         break;
  1722.         }
  1723.     }
  1724.     if ((multext ==    0) && (*t == '\0'))
  1725.         return (0);            /* Reject single term */
  1726.     if ((t2    = IsRegister (s, t-s)) < 0)
  1727.         return (0);            /* Not a recognizable register */
  1728.  
  1729.     if (!range) {
  1730.         multext |= (1 << t2);    /* Single register */
  1731.         t1 = t2;        /* Save    number in case it's a range */
  1732.     } else {            /* Range of registers */
  1733.         range = FALSE;
  1734.         if (t1 > t2) {
  1735.         j = t1;            /* Swap    registers if backwards */
  1736.         t1 = t2;
  1737.         t2 = j;
  1738.         }
  1739.         for    (j = t1; j <= t2; j++)
  1740.         multext    |= (1 << j);    /* Mark    all registers in range */
  1741.         if (*t == '-')
  1742.         return (0);        /* Invalid range */
  1743.     }
  1744.     if (*t == '\0')
  1745.         break;            /* Normal end of operand */
  1746.     if (*t++ == '-')
  1747.         range = TRUE;        /* Range indicator */
  1748.     if (*t == '\0')
  1749.         return (0);            /* Premature end of operand */
  1750.     s = t;
  1751.     }
  1752.     return (multext);
  1753. }
  1754.  
  1755.  
  1756.  
  1757. int GetAReg (op, len, loc) char    *op; int len, loc;
  1758. /* Validate an address register    specification.
  1759.     Valid specifications are A0    through    A7 , SP, or an EQUR label.
  1760.     The    address    register number    will be    returned if it is valid.
  1761.     Otherwise, Error will be called, using "loc" for the error
  1762.     location (this is its only use), and zero (A0) will    be returned. */
  1763. {
  1764.     register int i;
  1765.  
  1766.     i =    IsRegister (op,    len);        /* Get register    number */
  1767.     if ((i >= 8) && (i <= 15))
  1768.     return (i - 8);            /* Valid address register */
  1769.     else {
  1770.     Error (loc, AddrErr);        /* Not an address register */
  1771.     return (0);            /* Set to A0 */
  1772.     }
  1773. }
  1774.  
  1775.  
  1776.  
  1777. int IsRegister (op, len) char *op; int len;
  1778. /* Check whether the current operand is    an address or data register.
  1779.     Valid specifications are D0    throuth    D7, A0 through A7, SP,
  1780.     or any symbol equated to a register    with the EQUR directive.
  1781.     Return values:
  1782.     0 through 7 - data registers 0 through 7 respectively
  1783.     8 through 15 - address registers 0 through 7 respectively
  1784.     -1 - not a recognizable    register
  1785.     -2 - Equated register list for MOVEM instruction (REG)    */
  1786. {
  1787.     char tempop[MAXLINE];
  1788.     register char *s;
  1789.     register int  i;
  1790.  
  1791.     if (len == 2) {        /* Two-character specification */
  1792.     i = toupper (*op);
  1793.     s = op + 1;
  1794.     if ((i == 'S') && (toupper (*s) == 'P')) {
  1795.         return (15);        /* Stack Pointer */
  1796.     } else if ((*s >= '0') && (*s <= '7')) {
  1797.         if (i == 'A') {
  1798.         return (*s - '0' + 8);  /* Address Register */
  1799.         } else if (i == 'D') {
  1800.         return (*s - '0');      /* Data Register */
  1801.         }
  1802.     }
  1803.     }
  1804.     if (!GotEqur)            /* If we have no EQURs to check    */
  1805.     return (-1);            /*  don't waste any time here.  */
  1806.     for    (i = 0,    s = op;    i < len; i++) {
  1807.     if (IsOperator (s))
  1808.         return (-1);        /* It sure isn't a label */
  1809.     tempop[i] = *s++;
  1810.     }
  1811.     tempop[i] =    '\0';
  1812.     if (ReadSymTab (tempop)) {
  1813.     if (Sym->Flags & 0x60) {
  1814.         AddRef (LineCount);        /* Found a register or list */
  1815.         return ((Sym->Flags    & 0x20)    ? (int)    Sym->Val : -2);
  1816.     }
  1817.     }
  1818.     return (-1);            /* Not a recognizable register */
  1819. }
  1820.  
  1821.  
  1822.  
  1823. int GetInstModeSize (Mode) register int    Mode;
  1824. /* Determines the size for the various instruction modes. */
  1825. {
  1826.     switch (Mode) {
  1827.     case ARDisp:
  1828.     case ARDisX:
  1829.     case PCDisp:
  1830.     case PCDisX:
  1831.     case AbsW:
  1832.         return (2);
  1833.     case AbsL:
  1834.         return (4);
  1835.     case MultiM:
  1836.         return (0);        /* Accounted for by code generator */
  1837.     case Imm:
  1838.         if (Size ==    Long)
  1839.         return (4);
  1840.         else
  1841.         return (2);
  1842.     default:
  1843.         return (0);
  1844.     }
  1845. }
  1846. SHAR_EOF
  1847. #    End of shell archive
  1848. exit 0
  1849. -- 
  1850. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1851. Have five nice days.
  1852.